package com.fc.service.impl;

import cn.hutool.core.bean.BeanUtil;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.fc.context.BaseContext;
import com.fc.dto.IncomeDTO;
import com.fc.dto.pageQuery.IncomePageQueryDTO;
import com.fc.entity.Assessment;
import com.fc.entity.Expense;
import com.fc.entity.Income;
import com.fc.entity.Logistics;
import com.fc.enums.ReviewStatus;
import com.fc.exception.IncomeException;
import com.fc.mapper.IncomeMapper;
import com.fc.result.PageResult;
import com.fc.service.IAssessmentService;
import com.fc.service.IExpenseService;
import com.fc.service.IIncomeService;
import com.fc.service.ILogisticsService;
import com.fc.utils.MonthDaysUtil;
import com.fc.vo.DailyIncomeVO;
import com.fc.vo.LogisticsDetailVO;
import com.fc.vo.MonthlyIncomeVO;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.math.BigDecimal;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.LocalTime;
import java.time.format.DateTimeFormatter;
import java.time.temporal.TemporalAdjusters;
import java.util.ArrayList;
import java.util.List;
import java.util.Objects;

@Service
public class IncomeServiceImpl extends ServiceImpl<IncomeMapper, Income> implements IIncomeService {

    @Autowired
    private ILogisticsService logisticsService;

    @Autowired
    private IAssessmentService assessmentService;

    @Autowired
    private IExpenseService expenseService;

    @Autowired
    @Qualifier("bigDecimalRedisTemplate")
    private RedisTemplate<String, BigDecimal> bigDecimalRedisTemplate;

    /**
     * 司机日常收入
     *
     * @return
     */

    @Override
    public DailyIncomeVO daily() {

        LocalDate currentDate = LocalDate.now();
        //暂时每天收入只计算完成运输后的计件收入
        Long driverId = BaseContext.getCurrentId();
        LocalDateTime start = LocalDateTime.of(currentDate, LocalTime.MIN);
        LocalDateTime end = LocalDateTime.of(currentDate, LocalTime.MAX);
        List<Logistics> logisticsList = logisticsService.getByDriverIdAndTimeRange(driverId, start, end);
        BigDecimal dailyIncome = BigDecimal.ZERO;
        if (logisticsList.isEmpty()) {
            return new DailyIncomeVO(dailyIncome, logisticsList);
        }
        //获取保底工资
        int days = MonthDaysUtil.getCurrentMonthDays();
        Income income = getIncome(driverId);
        if(income==null){
            throw new IncomeException("该司机未设置保底工资");
        }
        BigDecimal dayOfBasicSalary = income.getBasicSalary().divide(BigDecimal.valueOf(days));

        //物流收入
        String date = LocalDate.now().format(DateTimeFormatter.BASIC_ISO_DATE); // 例如：20240405
        String key = "driver:income:day:" + BaseContext.getCurrentId() + ":" + date;
        BigDecimal logisticsDayIncome = bigDecimalRedisTemplate.opsForValue().get(key);

        if (logisticsDayIncome != null) {
            //日收入
            dailyIncome = dayOfBasicSalary.add(logisticsDayIncome);
        }
        return new DailyIncomeVO(dailyIncome, logisticsList);
    }

    @Transactional
    @Override
    public MonthlyIncomeVO monthly() {
        Long driverId = BaseContext.getCurrentId();
        LocalDateTime now = LocalDateTime.now();
        //计算公式：司机收入=保底工资+计件收入+绩效考核
        //计算总的计件收入
        LocalDateTime begin = now.with(TemporalAdjusters.firstDayOfMonth());//当前月份开始时间
        LocalDateTime end = now.with(TemporalAdjusters.lastDayOfMonth());//当前月份结束时间
        List<Logistics> logisticsList = logisticsService.getByDriverIdAndTimeRange(driverId, begin, end);
        //在这个列表中调用Logistics的getLogisticsIncome方法获取一趟运输的收入，累加到总收入上
        //计件单价之和
        BigDecimal logisticsIncome = BigDecimal.ZERO;
        if (!logisticsList.isEmpty()) {
            logisticsIncome = logisticsList.stream().map(Logistics::getLogisticsIncome)
                    .filter(Objects::nonNull)
                    .reduce(BigDecimal.ZERO, BigDecimal::add);
        }
        //客户单价之和
        BigDecimal performanceSalary = BigDecimal.ZERO;
        if (!logisticsList.isEmpty()) {
            performanceSalary=logisticsList.stream().map(Logistics::getPrice)
                    .filter(Objects::nonNull)
                    .reduce(BigDecimal.ZERO, BigDecimal::add);
        }

        //保底工资
        Income income = getIncome(driverId);
        if (income == null) {
            throw new IncomeException("该司机未设置保底工资");
        }
        BigDecimal basicSalary = income.getBasicSalary();
        /*//绩效工资
        Assessment assessment = getAssessment(driverId);
        if (assessment == null) {
            throw new IncomeException("未进行绩效考核，无法查看当前月收入");
        }
        BigDecimal bonusIncome = BigDecimal.valueOf((long) assessment.getScore() * assessment.getBonus());

        //总收入
        BigDecimal monthlyIncome = logisticsIncome.add(basicSalary).add(bonusIncome);

        // 将计算出来的收入存入数据库
        income.setLogisticsIncome(logisticsIncome);
        income.setBonusIncome(bonusIncome);
        income.setMonthlyIncome(monthlyIncome);
        income.setUpdateTime(LocalDateTime.now());
        updateById(income);

        return new MonthlyIncomeVO(monthlyIncome, basicSalary, logisticsIncome, bonusIncome);*/
        //总收入
        BigDecimal monthlyIncome = logisticsIncome.add(basicSalary);

        //总支出
        BigDecimal expenditureSalary=BigDecimal.ZERO;
        List<Expense> expenseList = expenseService.query()
                .eq("driver_id",driverId)
                .between("date",begin,end)
                .list();
        if (!expenseList.isEmpty()) {
            //计算支出总和
            expenditureSalary = expenseList.stream()
                    .map(Expense::getTotal)
                    .filter(Objects::nonNull)
                    .reduce(BigDecimal.ZERO, BigDecimal::add);
        }

        // 将计算出来的收入存入数据库
        income.setLogisticsIncome(logisticsIncome);
        income.setMonthlyIncome(monthlyIncome);
        income.setUpdateTime(LocalDateTime.now());
        updateById(income);

        return new MonthlyIncomeVO(monthlyIncome,performanceSalary, expenditureSalary);

    }

    @Override
    public void setSalary(IncomeDTO incomeDTO) {
        Long driverId = incomeDTO.getDriverId();
        Income income = getIncome(driverId);
        if (income != null) {
            throw new IncomeException("该司机用户已设置保底工资");
        }
        LocalDate now = LocalDate.now();
        save(Income.builder()
                .year(now.getYear())
                .month(now.getMonthValue())
                .driverId(driverId)
                .basicSalary(incomeDTO.getBasicSalary())
                .createTime(LocalDateTime.now())
                .updateTime(LocalDateTime.now())
                .build());
    }


    @Override
    public PageResult listIncome(IncomePageQueryDTO incomePageQueryDTO) {
        Page<Income> page = new Page<>(incomePageQueryDTO.getPageNum(), incomePageQueryDTO.getPageSize());
        Long driverId = incomePageQueryDTO.getDriverId();
        Integer year = incomePageQueryDTO.getYear();
        Integer month = incomePageQueryDTO.getMonth();
        Page<Income> pageResult = lambdaQuery()
                .eq(driverId != null, Income::getDriverId, driverId)
                .eq(year != null, Income::getYear, year)
                .eq(month != null, Income::getMonth, month)
                .orderByDesc(Income::getUpdateTime)
                .page(page);
        return new PageResult(pageResult.getTotal(), pageResult.getRecords());
    }

    @Override
    public void updateSalary(IncomeDTO incomeDTO) {
        Income income = getById(incomeDTO.getId());
        Long driverId = income.getDriverId();
        if (driverId != null) {
            income.setDriverId(driverId);
        }
        income.setBasicSalary(incomeDTO.getBasicSalary());
        BigDecimal monthlyIncome = income.getMonthlyIncome();
        if (monthlyIncome != null) {
            monthlyIncome = income.getBasicSalary().add(income.getLogisticsIncome()).add(income.getBonusIncome());
            income.setMonthlyIncome(monthlyIncome);
        }
        updateById(income);
    }

    @Override
    public List<LogisticsDetailVO> detail() {
        List<Logistics> logisticsList = logisticsService.list();
        if (logisticsList.isEmpty()) {
            return List.of();
        }
        List<LogisticsDetailVO> logisticsDetailVOList = new ArrayList<>();
        for (Logistics logistics : logisticsList) {
            BigDecimal totalExpense = BigDecimal.ZERO;
            List<Expense> expenseList = expenseService.query()
                    .eq("logistics_id", logistics.getId())
                    .eq("status", ReviewStatus.APPROVE.getCode())
                    .list();
            if (!expenseList.isEmpty()) {
                //计算支出总和
                totalExpense = expenseList.stream()
                        .map(Expense::getTotal)
                        .filter(Objects::nonNull)
                        .reduce(BigDecimal.ZERO, BigDecimal::add);
            }
            LogisticsDetailVO logisticsDetailVO = BeanUtil.copyProperties(logistics, LogisticsDetailVO.class);
            logisticsDetailVO.setExpenseList(expenseList);
            logisticsDetailVO.setTotalExpense(totalExpense);
            logisticsDetailVOList.add(logisticsDetailVO);
        }
        return logisticsDetailVOList;
    }

    private Income getIncome(Long driverId) {
        LocalDate now = LocalDate.now();
        QueryWrapper<Income> queryWrapper = new QueryWrapper<>();
        queryWrapper
                .eq("driver_id", driverId)
                .eq("year", now.getYear())
                .eq("month", now.getMonthValue());
        return getOne(queryWrapper);
    }

    private Assessment getAssessment(Long driverId) {
        LocalDate now = LocalDate.now();
        QueryWrapper<Assessment> queryWrapper = new QueryWrapper<>();
        queryWrapper
                .eq("driver_id", driverId)
                .eq("year", now.getYear())
                .eq("month", now.getMonthValue());
        return assessmentService.getOne(queryWrapper);
    }


}
